﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using StyleMVVM.Data;
using StyleMVVM.LanguageExtensions;
using StyleMVVM.Logging;

namespace StyleMVVM.Validation.Impl.Method
{
	public class ValidationMethodCollection<T> : IValidationMethodCollection<T>
	{
		private IReflectionService reflectionService;

		private readonly List<ValidationMethodDefinition<T>> validationMethodDefinitions =
			new List<ValidationMethodDefinition<T>>();

		private readonly List<string> validationProperties = new List<string>();

		private static string supplemental = typeof(ValidationMethodCollection<>).FullName;

		public IValidationMethodDefinition<T> AddRule(Action<IRuleExecutionContext<T>> validationMethod)
		{
			ValidationMethodDefinition<T> returnValue = new ValidationMethodDefinition<T>(reflectionService,
			                                                                              validationMethod,
			                                                                              null);

			validationMethodDefinitions.Add(returnValue);

			return returnValue;
		}

		public IValidationMethodDefinition<T> AddAsyncRule(Func<IRuleExecutionContext<T>, Task> validationMethod)
		{
			ValidationMethodDefinition<T> returnValue = new ValidationMethodDefinition<T>(reflectionService,
			                                                                              null,
			                                                                              validationMethod);

			validationMethodDefinitions.Add(returnValue);

			return returnValue;
		}

		public void ValidateProperty(Expression<Func<T, object>> property)
		{
			validationProperties.Add(
				reflectionService.GetPropertyAccessPath(property));
		}

		public IEnumerable<IValidationRule> AllRules()
		{
			List<IValidationRule> returnValue = new List<IValidationRule>();

			foreach (ValidationMethodDefinition<T> validationMethodDefinition in validationMethodDefinitions)
			{
				try
				{
					returnValue.Add(validationMethodDefinition.ProvideRule());
				}
				catch (Exception exp)
				{
					Logger.Error("Exception thrown while creating rule for type: " + typeof(T).FullName, supplemental, exp);
				}
			}

			return returnValue;
		}

		public IEnumerable<string> AllProperties()
		{
			return validationProperties;
		}
	}
}